《Android开源库》 Realm For Android~ Scheme & JSON & Notification(译文)

Scheme

Realm 使用所有项目中的 Realm 模型类来创建 schema。但这个行为是可以改变的,例如,你可以通过使用 RealmModule 让 Realm 只包含所有模型类的一个子集。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

// Create the module
@RealmModule(classes = { Person.class, Dog.class })
public class MyModule {
}

// Set the module in the RealmConfiguration to allow only classes defined by the module.
RealmConfiguration config = new RealmConfiguration.Builder()
.modules(new MyModule())
.build();

// It is possible to combine multiple modules to one schema.
RealmConfiguration config = new RealmConfiguration.Builder()
.modules(new MyModule(), new MyOtherModule())
.build();

共享schemas

库(library)开发者请注意: 在库中使用到的 Realm 必须通过 RealmModule 来暴露和使用其 schema。

这样可以防止库项目自动生成默认 RealmModule 从而避免和 app 生成的默认 RealmModule 冲突。库项目也是通过 RealmModule 来向 app 项目暴露自己的 Realm 模型类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Library must create a module and set library = true. This will prevent the default
// module from being created.
// allClasses = true can be used instead of listing all classes in the library.
@RealmModule(library = true, allClasses = true)
public class MyLibraryModule {
}

// Library projects are therefore required to explicitly set their own module.
RealmConfiguration libraryConfig = new RealmConfiguration.Builder()
.name("library.realm")
.modules(new MyLibraryModule())
.build();

// Apps can add the library RealmModule to their own schema.
RealmConfiguration config = new RealmConfiguration.Builder()
.name("app.realm")
.modules(Realm.getDefaultModule(), new MyLibraryModule())
.build();

目前你不可以在一个 Realm 文件里声明多个 RealmModule。如果你有多个 RealmModule,你需要将它们声明在多个 Realm 文件中以确保每个文件只有一个 RealmModule 声明。

这里有一个如何使用在库和 app 项目间使用 RealmModule 的完整例子

JSON

你可以直接将 JSON 对象添加到 Realm 中,这些 JSON 对象可以是一个 String、一个 JSONObject 或者是一个 InputStream。Realm 会忽略 JSON 中存在但未定义在 Realm 模型类里的字段。单独对象可以通过 Realm.createObjectFromJson() 添加。对象列表可以通过 Realm.createAllFromJson() 添加。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// A RealmObject that represents a city
public class City extends RealmObject {
private String city;
private int id;
// getters and setters left out ...
}

// Insert from a string
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
realm.createObjectFromJson(City.class, "{ city: \"Copenhagen\", id: 1 }");
}
});

// Insert multiple items using an InputStream
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
try {
InputStream is = new FileInputStream(new File("path_to_file"));
realm.createAllFromJson(City.class, is);
} catch (IOException e) {
throw new RuntimeException();
}
}
});

Realm 解析 JSON 时遵循如下规则:

  1. 使用包含空值(null)的 JSON 创建对象: 1) 对于非必须(可为空值的属性),设置其值为 null; 2) 对于必须(不可为空值的属性),抛出异常;
  2. 使用包含空值(null)的 JSON 更新对象: 1)对于非必须(可为空值的属性),设置其值为 null; 2) 对于必须(不可为空值的属性),抛出异常;
  3. 使用不包含对应属性的 JSON: 1)该属性保持不变

通知(Notifications)

Listener 只工作于 Looper 线程。对于非 Looper 线程请使用 Realm.waitForChange()。

Realm Notification

当后台线程向 Realm 添加数据,你的 UI 线程或者其它线程可以添加一个监听器来获取数据改变的通知。监听器在 Realm 数据改变的时候会被触发。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class MyActivity extends Activity {
private Realm realm;
private RealmChangeListener realmListener;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
realm = Realm.getDefaultInstance();
realmListener = new RealmChangeListener() {
@Override
public void onChange(Realm realm) {
// ... do something with the updates (UI, etc.) ...
}};
realm.addChangeListener(realmListener);
}

@Override
protected void onDestroy() {
super.onDestroy();
// Remove the listener.
realm.removeChangeListener(realmListener);
// Close the Realm instance.
realm.close();
}
}

除了在 Realm 实例上添加监听器以外,你还可以在 RealmObject 和 RealmResults 实例上添加监听器。你可以通过这样的方式来监视对象和查询结果的改变。另外,当监听回调函数被调用时,相应的数据已经被更新,你不需要去做刷新操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class MyActivity extends Activity {
private Realm realm;
private RealmChangeListener puppiesListener;
private RealmChangeListener dogListener;

private RealmResults<Dog> puppies;
private Dog dog;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
realm = Realm.getDefaultInstance();
puppiesListener = new RealmChangeListener() {
@Override
public void onChange(RealmResults<Dog> puppies) {
// ... do something with the updated puppies instance
}};

// Find all the puppies
puppies = realm.where(Dog.class).lessThanOrEqualTo("age", 2).findAll();
puppies.addChangeListener(puppiesListener);

dogListener = new RealmChangeListener() {
@Override
public void onChange(Dog dog) {
// ... do something with the updated Dog instance
}};

dog = realm.where(Dog.class).equalTo("name", "Fido").findFirst();
dog.addChangeListener(dogListener);
}

@Override
protected void onDestroy() {
super.onDestroy();
// Remove the listeners
puppies.removeChangeListener(puppiesListener);
dog.removeChangeListener(dogListener);
// Close the Realm instance.
realm.close();
}
}

你可以轻松移除所有监听器。

1
realm.removeAllChangeListeners();

最后,这些监听器同样会在监听对象的引用对象改变时被触发,请见示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Person person = realm.where(Person.class).findFirst();
person.getDogs(); // => 2 - Assume there are 2 dogs in the list
person.addChangeListener(new RealmChangeListener() {
@Override
public void onChange(Person person) {
// React to the change in the Person instance.
// This will also get called when any referenced dogs are updated.
}
});
Dog dog = person.getDogs().get(0);
realm.beginTransaction();
dog.setAge(5);
realm.commitTransaction();
// Person change listener is called on the next iteration of the run loop because
// a referenced dog object changed.

Collection Notifications

集合通知与Realm通知不同,因为它们包含描述在细粒度级别发生的更改的信息。 这包括自上次通知以来已插入,删除或修改的对象的索引。
集合通知是异步传递的,首先是初始结果,然后是在修改集合中的任何一个或者多个对象的写入事务之后,这个结果都会被重新初始化。
这些更改可以通过传递给更改侦听器的OrderedCollectionChangeSet参数访问。 此对象保存有关由删除,插入和更改影响的索引的信息。
删除和插入,当对象开始和停止是集合的一部分时记录索引。 这会考虑到何时将对象添加到领域或从领域中删除它们。 对于RealmResults,当你筛选特定值并且对象已更改,以使其现在匹配查询或不再匹配时,这也适用。
当对象的字段发生更改时,系统会通知你有关更改的信息,该字段以前是集合的一部分,但仍属于集合的一部分。 当一对一和多对多关系改变时,这种情况也会发生。

1
2
3
4
5
6
7
8
9
public class Dog extends RealmObject {
public String name;
public int age;
}

public class Person exteds RealmObject {
public String name;
public RealmList<Dog> dogs;
}

让我们假设你遵守上面的模型代码给出的狗主人列表。 你将收到关于匹配的Person对象的修改的通知,例如:

  • 修改Person的名字
  • 从一个Person拥有的狗的列表中增加或者删除一个
  • 修改属于这个人的一条狗的年龄

这使得可以离散地控制对UI中的内容进行的动画和视觉更新,而不是在每次发生通知时任意重新加载所有内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private final OrderedRealmCollectionChangeListener<RealmResults<Person>> changeListener = new OrderedRealmCollectionChangeListener() {
@Override
public void onChange(RealmResults<Person> collection, OrderedCollectionChangeSet changeSet) {
// `null` means the async query returns the first time.
if (changeSet == null) {
notifyDataSetChanged();
return;
}
// For deletions, the adapter has to be notified in reverse order.
OrderedCollectionChangeSet.Range[] deletions = changeSet.getDeletionRanges();
for (int i = deletions.length - 1; i >= 0; i--) {
OrderedCollectionChangeSet.Range range = deletions[i];
notifyItemRangeRemoved(range.startIndex, range.length);
}

OrderedCollectionChangeSet.Range[] insertions = changeSet.getInsertionRanges();
for (OrderedCollectionChangeSet.Range range : insertions) {
notifyItemRangeInserted(range.startIndex, range.length);
}

OrderedCollectionChangeSet.Range[] modifications = changeSet.getChangeRanges();
for (OrderedCollectionChangeSet.Range range : modifications) {
notifyItemRangeChanged(range.startIndex, range.length);
}
}
};

RealmRecyclerViewAdapter 也可以达到同样的效果.

原文链接

https://realm.io/docs/java/latest/#schemas

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×